package com.ganbing518.commons.utils;

import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public interface RsaUtil {

    String SIGN_ALGORITHMS_SHA1 = "SHA1WithRSA";

    String SIGN_ALGORITHMS_SHA256 = "SHA256WithRSA";

    String SIGN_ALGORITHMS_SHA512 = "SHA512WithRSA";

    static byte[] signWithSHA256(String content, String privateKey) throws Exception {
        return sign(content, privateKey, SIGN_ALGORITHMS_SHA256);
    }

    static boolean verifyWithSHA256(String content, byte[] sign, String publicKey) throws Exception {
        return verify(content, sign, publicKey, SIGN_ALGORITHMS_SHA256);
    }

    static byte[] sign(String content, String privateKey, String algorithm) throws Exception {
        return sign(content, privateKey, Charsets.UTF_8.displayName(), algorithm);
    }

    static boolean verify(String content, byte[] sign, String publicKey, String algorithm) throws Exception {
        return verify(content, sign, publicKey, Charsets.UTF_8.displayName(), algorithm);
    }

    static byte[] sign(String content, String privateKey, String encode, String algorithm) throws Exception {

        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyFactory.generatePrivate(encodedKeySpec);

        Signature signature = Signature.getInstance(algorithm);
        signature.initSign(priKey);
        signature.update(content.getBytes(encode));

        return signature.sign();
    }

    static boolean verify(String content, byte[] sign, String publicKey, String encode, String algorithm) throws Exception {

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] encodedKey = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(encodedKey);
        PublicKey pubKey = keyFactory.generatePublic(encodedKeySpec);

        Signature signature = Signature.getInstance(algorithm);
        signature.initVerify(pubKey);
        signature.update(content.getBytes(encode));

        return signature.verify(sign);
    }
}
